package com.spark.gaea.utils;

import com.google.common.collect.Lists;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public final class ClassUtil {
	public static List<Class> getAllClassByInterface(final Class c) {
		List<Class> returnClassList = null;
		if (c.isInterface()) {
			final String packageName = c.getPackage().getName();
			final List<Class<?>> allClass = getClasses(packageName);
			if (allClass != null) {
				returnClassList = Lists.newArrayList();
				for (final Class classes : allClass) {
					if (c.isAssignableFrom(classes) && !c.equals(classes)) {
						returnClassList.add(classes);
					}
				}
			}
		}
		return returnClassList;
	}

	public static String[] getPackageAllClassName(final String classLocation, final String packageName) {
		final String[] packagePathSplit = packageName.split("[.]");
		String realClassLocation = classLocation;
		for (final String aPackagePathSplit : packagePathSplit) {
			realClassLocation = realClassLocation + File.separator + aPackagePathSplit;
		}
		final File packeageDir = new File(realClassLocation);
		if (packeageDir.isDirectory()) {
			return packeageDir.list();
		}
		return null;
	}

	public static List<Class<?>> getClasses(String packageName) {
		final List<Class<?>> classes = Lists.newArrayList();
		final boolean recursive = true;
		final String packageDirName = packageName.replace('.', '/');
		try {
			final Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			while (dirs.hasMoreElements()) {
				final URL url = dirs.nextElement();
				final String protocol = url.getProtocol();
				if ("file".equals(protocol)) {
					final String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else {
					if (!"jar".equals(protocol)) {
						continue;
					}
					try {
						final JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
						final Enumeration<JarEntry> entries = jar.entries();
						while (entries.hasMoreElements()) {
							final JarEntry entry = entries.nextElement();
							String name = entry.getName();
							if (name.charAt(0) == '/') {
								name = name.substring(1);
							}
							if (name.startsWith(packageDirName)) {
								final int idx = name.lastIndexOf(47);
								if (idx != -1) {
									packageName = name.substring(0, idx).replace('/', '.');
								}
								if ((idx == -1 && !recursive) || !name.endsWith(".class") || entry.isDirectory()) {
									continue;
								}
								final String className = name.substring(packageName.length() + 1, name.length() - 6);
								try {
									classes.add(Class.forName(packageName + '.' + className));
								} catch (ClassNotFoundException e) {
									e.printStackTrace();
								}
							}
						}
					} catch (IOException e2) {
						e2.printStackTrace();
					}
				}
			}
		} catch (IOException e3) {
			e3.printStackTrace();
		}
		return classes;
	}

	public static void findAndAddClassesInPackageByFile(final String packageName, final String packagePath,
			final boolean recursive, final List<Class<?>> classes) {
		final File dir = new File(packagePath);
		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		final File[] arr$;
		final File[] dirfiles = arr$ = dir.listFiles(new FileFilter() {
			@Override
			public boolean accept(final File file) {
				return (recursive && file.isDirectory()) || file.getName().endsWith(".class");
			}
		});
		for (final File file : arr$) {
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
						classes);
			} else {
				final String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					classes.add(Class.forName(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
